/*
 *
 * File Name: dbus_server.c
 * Author: liaoxuecheng
 * mail: liaoxuecheng@hotmail.com
 * Created Time: 2024年12月24日 星期二 17时17分21秒
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <dbus/dbus.h>

#include "at_dbus.h"
#include "tests.h"

#define THIS_FILE "dbus_server.c"

#ifndef PJ_LOG
#define TEST_PRINTF(title,fmt,arg...) printf("%s:%d %s, "fmt, __func__, __LINE__, title, ##arg)
#define PJ_LOG(arg, fmt) printf("level = %d, ",arg);TEST_PRINTF fmt;
#endif

static DBusHandlerResult handle_echo(DBusConnection *connection, DBusMessage *message)
{
    char *msg = NULL;
    at_variant *variant = get_variant_from_message(message);
    if(variant == NULL)
    {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
    at_variant_get(variant, "s", &msg);
    PJ_LOG(4, (THIS_FILE, "client_msg:%s\n", msg));
    at_variant *response = at_variant_new("s", "Hello client!");
    if(response == NULL)
    {
        PJ_LOG(4, (THIS_FILE, "\n"));
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
    at_dbus_send_message_response_success(connection, message, response);
    at_variant_free(variant);
    at_variant_free(response);
    PJ_LOG(4, (THIS_FILE, "\n"));
    return DBUS_HANDLER_RESULT_HANDLED;
}

static void path_unregistered_func(DBusConnection *connection, void *user_data)
{
    /* connection was finalized */
}

static DBusHandlerResult path_message_func(DBusConnection *connection, DBusMessage *message, void *user_data)
{
    PJ_LOG(4, (THIS_FILE, "\n"));
    if(dbus_message_is_method_call(message, SERVER_OBJ_INTERFACE, "Echo")) {
        return handle_echo(connection, message);
    }
    PJ_LOG(4, (THIS_FILE, "\n"));
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

static DBusObjectPathVTable echo_vtable = {
    path_unregistered_func,
    path_message_func,
    NULL,
};

static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data)
{
    if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
    {
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    else
    {
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    }
}

void *dbus_main_loop_func(void *arg)
{
    int ret = 0;
    void *d = NULL;
    DBusError error;
    DBusConnection *connection;
    dbus_error_init (&error);

    /* dbus_bus_get_private 只能注册signal信号 无法注册method信号 */
    connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
    if(connection == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to open connection: %s\n", error.message));
        dbus_error_free (&error);
        return NULL;
    }

    ret = dbus_bus_request_name(connection, SERVER_OBJ_NAME, 0, &error);
    if(dbus_error_is_set(&error))
    {
        PJ_LOG(1, (THIS_FILE, "Failed request bus name: %s\n", error.message));
        dbus_error_free (&error);
        exit(1);
    }

    if(ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
        PJ_LOG(1, (THIS_FILE, "Unable to acquire service: code %d\n", ret));
        exit(1);
    }

    if(!dbus_connection_add_filter (connection, filter_func, NULL, NULL))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }

    test_vtable_register_object_path(connection);
    if(!dbus_connection_register_object_path (connection, SERVER_OBJ_PATH, &echo_vtable, (void*) 0xdeadbeef))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }

    if (!dbus_connection_get_object_path_data (connection, SERVER_OBJ_PATH, &d))
    {
        PJ_LOG(1, (THIS_FILE, "No memory"));
        exit(1);
    }
    if (d != (void*)0xdeadbeef)
    {
        PJ_LOG(1, (THIS_FILE, "dbus_connection_get_object_path_data() doesn't seem to work right\n"));
        exit(1);
    }

    at_dbus_add_signal_match(connection, CLIENT_OBJ_NAME);
    /* type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
     * path='/bar/foo',destination=':452345.34' 
     */
    dbus_bus_add_match(connection,"type='signal',path='" CLIENT_OBJ_PATH "'",&error);
    PJ_LOG(1, (THIS_FILE, "server thread main loop running\n"));

    simple_loop(connection);

    /* dbus_connection_read_write dbus_connection_dispatch 效率低下, 优先使用dbus_connection_read_write_dispatch */
    while(dbus_connection_read_write_dispatch (connection, 100));

    while(1)
    {
        dbus_connection_read_write(connection, 1000);
        dbus_connection_dispatch(connection);
    }

    dbus_connection_remove_filter (connection, filter_func, NULL);
    dbus_connection_unref (connection);
    return 0;
}

int test_dbus_send_signal(at_proxy *test_proxy)
{
    DBusConnection *conn;
    DBusError error;
    at_variant *variant;

    dbus_error_init (&error);
    conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
    if(conn == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to open connection: %s\n", error.message));
        dbus_error_free (&error);
        return 1;
    }

    variant = at_variant_new("isud", 11, "hello signal!", 22, 33.33);
    at_dbus_send_signal(conn, test_proxy->object_path, test_proxy->interface, "signal_test", variant);
    at_variant_free(variant);
    dbus_connection_unref(conn);
    return 0;
}

int main(int argc, char **argv)
{
    pthread_t thread;
    at_proxy *test_proxy;
    static pthread_mutex_t mute = {0};
    dbus_threads_init_default();
    at_dbus_init_common_connection(&mute, 0);
    init_args(argc, argv);

    test_proxy = at_proxy_new(SERVER_OBJ_NAME, SERVER_OBJ_PATH, SERVER_OBJ_INTERFACE);
    if(test_proxy == NULL)
    {
        PJ_LOG(1, (THIS_FILE, "Failed to create proxy error\n"));
        exit(1);
    }

    pthread_create(&thread, NULL, dbus_main_loop_func, NULL);

    while(1)
    {
        sleep(3);
        test_dbus_send_signal(test_proxy);
    }

    at_proxy_free(test_proxy);
    return 0;
}
